﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using EnvDTE;
using Microsoft.DataWarehouse.VsIntegration.Shell.Project.Extensibility;
using System.IO;

namespace SSISPackageExplorer.UI
{
    public partial class PackageExplorerTool : UserControl
    {
        public PackageExplorerTool()
        {
            InitializeComponent();
            Timer_Tick(this, EventArgs.Empty);
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            if (!Session.HasProject())
            {
                TreeView.Nodes.Clear();
                VisibleToolBar(false);
            }
            else
            {
                if (TreeView.Nodes.Count == 0)
                { 
                    RefreshTree();
                    VisibleToolBar(true);
                }

                EnableToolBar(!Session.HasReadonlyConfigFile());    
            }
        }

        #region UI
        private void VisibleToolBar(bool visibled) 
        {
            RefreshToolStripButton.Visible = visibled;
            SaveToolStripButton.Visible = visibled;
            AddFolderToolStripButton.Visible = visibled;
            DeleteToolStripButton.Visible = visibled;
            FindToolStripTextBox.Visible = visibled;
            SeperatorToolStripButton1.Visible = visibled;
            SeperatorToolStripSeparator2.Visible = visibled;
            openToolStripMenuItem.Visible = visibled;
            newFolderToolStripMenuItem.Visible = visibled;
            deleteToolStripMenuItem.Visible = visibled;
            editToolStripMenuItem.Visible = visibled;
        }

        private void EnableToolBar(bool enabled)
        {
            SaveToolStripButton.Enabled = enabled;
            AddFolderToolStripButton.Enabled = enabled;
            DeleteToolStripButton.Enabled = enabled;
            TreeView.AllowDrop = enabled;
            newFolderToolStripMenuItem.Enabled = enabled;
            deleteToolStripMenuItem.Enabled = enabled;
            editToolStripMenuItem.Enabled = enabled;
        }

        private void RefreshToolStripButton_Click(object sender, EventArgs e)
        {
            RefreshTree();
        }

        private void SaveToolStripButton_Click(object sender, EventArgs e)
        {
            Save();
        }

        private void AddFolderToolStripButton_Click(object sender, EventArgs e)
        {
            AddFolder();
        }

        private void DeleteToolStripButton_Click(object sender, EventArgs e)
        {
            Delete();
        }

        private void TreeView_DragOver(object sender, DragEventArgs e)
        {
            if (e.Data != null && IsValidDrop(e))
            {
                e.Effect = DragDropEffects.Move;
                Point pt = ((TreeView)TreeView).PointToClient(new Point(e.X, e.Y));
                TreeNode targetNode = TreeView.GetNodeAt(pt);
                TreeView.SelectedNode = targetNode;
            }
                
            else
                e.Effect = DragDropEffects.None;
        }

        private void TreeView_DragDrop(object sender, DragEventArgs e)
        {
            DropNode(e);
        }

        private void TreeView_ItemDrag(object sender, ItemDragEventArgs e)
        {
            TreeView.DoDragDrop(e.Item, DragDropEffects.Move);
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Open(TreeView.SelectedNode);
        }

        private void newFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddFolder();
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Delete();
        }

        private void editToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Edit(TreeView.SelectedNode);
        }

        private void TreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            Open(e.Node);
        }

        private void FindToolStripTextBox_TextChanged(object sender, EventArgs e)
        {
            RefreshTree();
            if (FindToolStripTextBox.Text.Length > 0)
                TreeView.ExpandAll();
        }

        private void TreeView_AfterCollapse(object sender, TreeViewEventArgs e)
        {
            if (e.Node is FolderNode)
            {
                e.Node.ImageIndex = 1;
                e.Node.SelectedImageIndex = 1;
            }
        }

        private void TreeView_AfterExpand(object sender, TreeViewEventArgs e)
        {
            if (e.Node is FolderNode)
            {
                e.Node.ImageIndex = 2;
                e.Node.SelectedImageIndex = 2;
            }
        }

        private void HelpToolStripButton_Click(object sender, EventArgs e)
        {
            new Help().ShowDialog();
        }
        #endregion

        #region Commands
        private void RefreshTree() 
        {
            TreeView.Nodes.Clear();

            if (!Session.HasProject())
                return;

            foreach(Project proj in Session.GetProjectList())
            {
                LoadProject(proj);            
            }     
        }

        private void LoadProject(Project proj) 
        {

            List<PackageNode> PackageNodeList = new List<PackageNode>();

            foreach (ProjectItem item in proj.ProjectItems)
            {
                if (item.Name.Contains(".dtsx") && !TreeView.Nodes.ContainsKey(item.Name))
                {
                    PackageNodeList.Add(new PackageNode(item));
                }
            }

            Config.SSISPackageExplorerConfig config = Config.SSISPackageExplorerConfig.Load(proj);

            ProjectNode projNode = new ProjectNode(proj);
            projNode.Text = proj.Name;
            TreeView.Nodes.Add(projNode);

            LoadTreeFolderNodes(config, projNode);

            foreach (PackageNode pn in PackageNodeList)
            {
                Config.Package p = config.PackageList.Find(t => t.PackageName == pn.Text);
                if (p == null)
                    projNode.AddChild(pn);
                else
                {
                    NodeBase parent = FindTreeNode(p.PackageFolder, projNode.Nodes);
                    if (parent != null)
                        parent.AddChild(pn);
                    else
                        projNode.AddChild(pn);
                }
            }

            ApplySearchFilter(projNode);
        }

        private void ApplySearchFilter(NodeBase parent)
        {
            if (FindToolStripTextBox.Text.Length == 0)
                return;

            foreach (NodeBase node in parent.Nodes)
            {
                if (!node.SearchText.ToLower().Contains(FindToolStripTextBox.Text.ToLower()))
                    node.Remove();

                ApplySearchFilter(node);
            }
        
        }

        private NodeBase FindTreeNode(Guid guid, TreeNodeCollection nodes) 
        {
            foreach (TreeNode n in nodes) 
            {
                if (n is FolderNode && ((FolderNode)n).Guid.ToString() == guid.ToString())
                    return (NodeBase)n;

                if (n is PackageNode && ((PackageNode)n).Guid.ToString() == guid.ToString())
                    return (NodeBase)n;

                if (n.Nodes.Count != 0)
                    return FindTreeNode(guid, n.Nodes);
            }

            return null;
        }

        private void LoadTreeFolderNodes(Config.SSISPackageExplorerConfig config, NodeBase parentNode) 
        {
            foreach (Config.PackageFolder f in config.PackageFolderList.FindAll(t => t.ParentFolder.ToString() == parentNode.Guid.ToString()))
            {
                FolderNode fn = new FolderNode();
                fn.Guid = f.Guid;
                fn.Text = f.Name;
                parentNode.AddChild(fn);

                LoadTreeFolderNodes(config, fn);
            }
        }

        private void Save()
        {
            foreach (ProjectNode proj in TreeView.Nodes)
            {
                Config.SSISPackageExplorerConfig config = new SSISPackageExplorer.Config.SSISPackageExplorerConfig();

                SaveToConfig(config, proj);

                config.Save(proj.Project);
            }
        }

        private void Open(TreeNode node)
        {
            if (node is PackageNode)
                ((PackageNode)node).Open();

            if (node is FolderNode)
            {
                FolderEdit fe = new FolderEdit();
                fe.FolderName = node.Text;
                if (fe.ShowDialog() == DialogResult.OK)
                {
                    node.Text = fe.FolderName;
                }
            }
        }

        private void Edit(TreeNode node)
        {
            if (node is PackageNode)
            {
                PackageEdit pe = new PackageEdit((PackageNode)node);
                if (pe.ShowDialog() == DialogResult.OK)
                {
                    Save();
                }
            }
                

            if (node is FolderNode)
            {
                FolderEdit fe = new FolderEdit();
                fe.FolderName = node.Text;
                if (fe.ShowDialog() == DialogResult.OK)
                {
                    node.Text = fe.FolderName;
                    Save();
                }
            }
        }
        
        private void SaveToConfig(Config.SSISPackageExplorerConfig config, NodeBase treeNode)
        {
            foreach (NodeBase n in treeNode.Nodes)
            {
                if (n is FolderNode)
                {
                    Config.PackageFolder f = new SSISPackageExplorer.Config.PackageFolder();
                    f.Guid = ((FolderNode)n).Guid;
                    f.Name = n.Text;
                    f.ParentFolder = treeNode.Guid;
                    config.PackageFolderList.Add(f);
                    if (n.Nodes.Count != 0)
                        SaveToConfig(config, n);
                }
                else if (n is PackageNode)
                { 
                    Config.Package pg = new SSISPackageExplorer.Config.Package();
                    pg.PackageFolder = treeNode.Guid;
                    pg.PackageName = n.Text;
                    config.PackageList.Add(pg);
                }
                
            }        
        }
        
        private void AddFolder() 
        {
            if (TreeView.SelectedNode == null)
                return;

            NodeBase selected = (NodeBase)TreeView.SelectedNode;

            if (selected is ProjectNode || selected is FolderNode)
            { 
                FolderEdit fe = new FolderEdit();
                if (fe.ShowDialog() == DialogResult.OK)
                {
                    FolderNode newFolder = new FolderNode();
                    newFolder.Text = fe.FolderName;
                    newFolder.Guid = Guid.NewGuid();
                    selected.Nodes.Add(newFolder);
                    Save();
                }            
            }
        }
        
        private void Delete() 
        {
            TreeNode selected = TreeView.SelectedNode;

            if (selected == null)
                return;

            if (selected.Nodes.Count != 0)
                return;

            if (selected is FolderNode)
            {
                selected.Remove();
                Save();
            }      
        }

        private bool IsValidDrop(DragEventArgs e)
        {
            Point pt = ((TreeView)TreeView).PointToClient(new Point(e.X, e.Y));
            NodeBase targetNode = (NodeBase)TreeView.GetNodeAt(pt);

            NodeBase source = (NodeBase)e.Data.GetData(typeof(FolderNode));
            if (source == null)
                source = (NodeBase)e.Data.GetData(typeof(PackageNode));
            
            if (source.Equals(targetNode))
                return false;

            if (source.Parent.Equals(targetNode))
                return false;

            if (!GetProjectNode(source).Equals(GetProjectNode(targetNode)))
                return false;

            if (IsChildNode(source, targetNode))
                return false;

            return true;
        }

        private bool IsChildNode(NodeBase parent, NodeBase child)
        {
            if (child.Parent == null)
                return false;

            if (child.Equals(parent))
                return false;

            if (child.Parent.Equals(parent))
                return true;

            return IsChildNode(parent, (NodeBase)child.Parent);
        }

        private ProjectNode GetProjectNode(NodeBase node)
        {
            if (node is ProjectNode)
                return (ProjectNode)node;

            if (node.Parent is ProjectNode)
                return (ProjectNode)node.Parent;

            return GetProjectNode((NodeBase)node.Parent);
        }

        private void DropNode(DragEventArgs e)
        {
            if (!IsValidDrop(e))
                return;

            Point pt = ((TreeView)TreeView).PointToClient(new Point(e.X, e.Y));
            NodeBase targetNode = (NodeBase)TreeView.GetNodeAt(pt);

            NodeBase source = (NodeBase)e.Data.GetData(typeof(FolderNode));
            if (source == null)
                source = (NodeBase)e.Data.GetData(typeof(PackageNode));

            source.Remove();
            targetNode.Nodes.Add(source);
            Save();
        }
        #endregion






        
    }
}
